home *** CD-ROM | disk | FTP | other *** search
- /*
- Socks.c
-
- Socks library for my MacTCP library.
-
- This library provides an API for using MacTCP in conjunction with a Socks daemon
- to control access. It does not yet support async socks connections.
-
- 12/04/95 dn - Prep'd for Apprentice 4
- */
-
- #include <MyTCPIncludes.h>
-
- #include "Socks.h"
-
- /*
- Local Prototypes
- */
- OSErr SockdOpen(SOCKSiopbPtr pb);
- OSErr SocksRequest(SOCKSiopbPtr socksPB,char command);
- OSErr check_result(char code);
- OSErr Socks_ActiveOpenAsync(SOCKSiopb* pb);
- OSErr Socks_PassiveOpenAsync(SOCKSiopb* pb);
-
- /*
- SockdOpen
-
- Open a connection to the SOCKS daemon.
- */
- OSErr SockdOpen(SOCKSiopbPtr pb){
- OSErr err;
- ip_addr host;
- tcp_port port;
- TCPiopb open;
-
- open.ioCRefNum=pb->ioCRefNum;
- open.tcpStream=pb->tcpStream;
- open.csParam.open.ulpTimeoutValue=pb->csParam.open.ulpTimeoutValue;
- open.csParam.open.ulpTimeoutAction=pb->csParam.open.ulpTimeoutAction;
- open.csParam.open.validityFlags=pb->csParam.open.validityFlags;
- open.csParam.open.remoteHost=pb->csParam.open.socksHost;
- open.csParam.open.remotePort=pb->csParam.open.socksPort;
- open.csParam.open.tosFlags=pb->csParam.open.tosFlags;
- open.csParam.open.localPort=pb->csParam.open.localPort;
- open.csParam.open.precedence=pb->csParam.open.precedence;
- open.csParam.open.dontFrag=true;
- open.csParam.open.timeToLive=pb->csParam.open.timeToLive;
- open.csParam.open.security=pb->csParam.open.security;
- open.csParam.open.optionCnt=pb->csParam.open.optionCnt;
- if (open.csParam.open.optionCnt>0){
- BlockMoveData((Ptr)pb->csParam.open.options,(Ptr)open.csParam.open.options,
- open.csParam.open.optionCnt*sizeof(SInt8));
- }
- open.csParam.open.userDataPtr=pb->csParam.open.userDataPtr;
-
- // open the connection...
- err=TCP_ActiveOpen(&open,false);
-
- // save the local host and port back into the parm block before returning
- pb->csParam.open.localHost=open.csParam.open.localHost;
- pb->csParam.open.localPort=open.csParam.open.localPort;
-
- return err;
- }
-
- /*
- SocksRequest
-
- Requests a connection through the SOCKS daemon.
-
- The request works like this: after the connection to the socks daemon is opened, the
- first thing that must be sent to the daemon is an 8 byte packet which describes where the
- connection really should be made to (includes the address and port of the remote host). Following
- this packet is a null-terminated C-style string which contains the username of the user making the
- request. After this is transmitted to the socks daemon, it will process the request and return
- the 8 byte packet with a result code indicating the success/failure of the external connection.
-
- According to the SOCKS documentation, the socks daemon is supposed to use the username passed
- in during the connection request in a call to the local identd server (identd verifies the user actually
- has initiated the request). During my testing, though, the socks daemon did not fail with the 'no identd'
- error, even though I was not running an identd server. So either I was connecting to an old socks daemon
- (could be; I don't know what version the server is that was running), our socks daemon doesn't use
- the identd service, our socks daemon doesn't error if no local identd server is running, or the socks
- daemon ignored the absence of the identd server. I am not completely sure which option it was, but I
- tend to think that we are configured not to use the identd server (although I plan on writing one for
- my mac anyway).
- */
- OSErr SocksRequest(SOCKSiopbPtr socksPB,char command){
- char c[200];
- OSErr err;
- TCPiopb pb;
- wdsEntry wds[3];
- short have;
-
- union {
- tcp_port port;
- char ch[2];
- } aPort;
-
- union {
- ip_addr addr;
- char ch[4];
- } aAddr;
-
- // set up our TCPiopb
- pb.tcpStream=socksPB->tcpStream;
- pb.ioCRefNum=socksPB->ioCRefNum;
- pb.csParam.send.ulpTimeoutValue=0;
- pb.csParam.send.ulpTimeoutAction=0;
- pb.csParam.send.wdsPtr=(Ptr)wds;
- pb.csParam.send.pushFlag=2; // send right away, no delay
- pb.csParam.send.urgentFlag=0;
-
- c[0]=SOCKS_VERSION;
- c[1]=command;
- aPort.port=socksPB->csParam.open.remotePort;
- c[2]=aPort.ch[0];c[3]=aPort.ch[1];
- aAddr.addr=socksPB->csParam.open.remoteHost;
- c[4]=aAddr.ch[0];c[5]=aAddr.ch[1];
- c[6]=aAddr.ch[2];c[7]=aAddr.ch[3];
-
- // set up the wdsEntry structures
-
- // first is the Socks_t struct
- wds[0].length=8;
- wds[0].ptr=(Ptr)c;
-
- // next is the user's name
- wds[1].length=StrLen(socksPB->csParam.open.socksUser)+1;
- wds[1].ptr=(Ptr)socksPB->csParam.open.socksUser;
-
- wds[2].length=0;
- wds[2].ptr=(Ptr)0;
-
- // send our stuff to the socks daemon
- err=TCP_Send(&pb,false); // send the item...
-
- if (err!=noErr)
- return err;
-
- // info sent, now we have to read the results back from the socks daemon
- // it is sent back in the form of a Socks_t structure.
-
- pb.tcpStream=socksPB->tcpStream;
- have=0;
-
- // loop until the entire Socks_T has been read from the socks host
- while (have<8){
- pb.csParam.receive.commandTimeoutValue=0;
- pb.csParam.receive.rcvBuff=(Ptr)(c+have);
- pb.csParam.receive.rcvBuffLen=200-have;
-
- // now read the Socks_t
- err=TCP_Rcv(&pb,false);
-
- if (err!=noErr)
- return err;
-
- have+=pb.csParam.receive.rcvBuffLen;
- }
-
- // depending on cmd, we may/may not have a connection...
- return check_result(c[1]);
- }
-
-
- /*
- check_result
-
- Converts the code from the socks daemon into a Mac OSErr.
- */
- OSErr check_result(char code){
- switch (code) {
- case SOCKS_FAIL:
- return socksConnFail;
- case SOCKS_NO_IDENTD:
- return socksNoIdentd;
- case SOCKS_BAD_ID:
- return socksBadID;
- default:
- return noErr;
- }
- }
-
- OSErr SOCKS_Create(SOCKSiopb * pb,Boolean async){
- return TCP_Create((TCPiopbPtr)pb,async);
- }
-
- /*
- SocksActiveOpen
-
- Opens an active connection after fixing the param block to go through
- the Socks daemon. Opens the connection, sends the Socks data structure,
- and if everything works out returns the correct and open tcp stream to
- the user.
- */
- OSErr SOCKS_ActiveOpen(SOCKSiopb* pb,Boolean async){
- OSErr err=noErr;
-
- if (async)
- return Socks_ActiveOpenAsync(pb);
-
- err=SockdOpen(pb);
-
- if (err!=noErr)
- return err;
-
- // the connection to the socks daemon is open, finish the open request
-
- err=SocksRequest(pb,SOCKS_ACTIVE_OPEN);
-
- return err;
- }
-
- OSErr SOCKS_PassiveOpen(SOCKSiopb * pb,Boolean async){
- OSErr err;
- short have=0;
- TCPiopb tcp;
- char c[10];
-
- union {
- tcp_port port;
- char ch[2];
- } aPort;
-
- union {
- ip_addr addr;
- char ch[4];
- } aAddr;
-
- if (async)
- return Socks_PassiveOpenAsync(pb);
-
- // open a connection to the socks daemon
- err=SockdOpen(pb);
-
- if (err!=noErr)
- return err;
-
- err=SocksRequest(pb,SOCKS_PASSIVE_OPEN);
-
- if (err!=noErr)
- return err;
-
- /*
- At this point an active connection has been opened with the socks daemon. It is listening for
- an incoming connection. When it returns data back to us (specifically the 8 byte structure mentioned
- in SOCKS_ActiveOpen()), a connection request has been received by the socks daemon, and we can begin.
- */
-
- tcp.tcpStream=pb->tcpStream;
- tcp.ioCRefNum=pb->ioCRefNum;
-
- // loop until the entire Socks_T has been read from the socks host
- while (have<8){
- tcp.csParam.receive.commandTimeoutValue=0;
- tcp.csParam.receive.rcvBuff=(Ptr)(c+have);
- tcp.csParam.receive.rcvBuffLen=10-have;
-
- // now read the Socks_t
- err=TCP_Rcv(&tcp,false);
-
- if (err!=noErr)
- return err;
-
- have+=tcp.csParam.receive.rcvBuffLen;
- }
-
- // the connection request has completed
- // fill out the remaining structures of the SOCKSiopb before returning
- aPort.ch[0]=c[2];aPort.ch[1]=c[3];
- aAddr.ch[0]=c[4];aAddr.ch[1]=c[5];aAddr.ch[2]=c[6];aAddr.ch[3]=c[7];
-
- pb->csParam.open.remoteHost=aAddr.addr;
- pb->csParam.open.remotePort=aPort.port;
-
- return noErr;
- }
-
- OSErr SOCKS_Send(SOCKSiopb * pb,Boolean async){
- return TCP_Send((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_NoCopyRcv(SOCKSiopb * pb,Boolean async){
- return TCP_NoCopyRcv((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_RcvBfrReturn(SOCKSiopb * pb,Boolean async){
- return TCP_RcvBfrReturn((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_Rcv(SOCKSiopb * pb,Boolean async){
- return TCP_Rcv((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_Close(SOCKSiopb * pb,Boolean async){
- return TCP_Close((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_Abort(SOCKSiopb * pb,Boolean async){
- return TCP_Abort((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_Status(SOCKSiopb * pb,Boolean async){
- return TCP_Status((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_ExtendedStat(SOCKSiopb * pb,Boolean async){
- return TCP_ExtendedStat((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_Release(SOCKSiopb * pb,Boolean async){
- return TCP_Release((TCPiopbPtr)pb,async);
- }
-
- OSErr SOCKS_GlobalInfo(SOCKSiopb * pb,Boolean async){
- return TCP_GlobalInfo((TCPiopbPtr)pb,async);
- }
-
- /*
- Socks_ActiveOpenAsync
-
- When opening a connection asynchronously, the library is going to have to chain the process together,
- not returning to the user until the connection is finally established.
-
- The best bet is to put the user's ioCompletion routine in the userDataPtr field to pass it around. Replace
- the completion procs with our procs in the chain. When done, call the user's proc with the completed
- parm block.
- */
- OSErr Socks_ActiveOpenAsync(SOCKSiopb* pb){
- return paramErr;
- }
-
- /*
- Socks_PassiveOpenAsync
-
- When opening a connection asynchronously, the library is going to have to chain the process together,
- not returning to the user until the connection is finally established.
-
- The best bet is to put the user's ioCompletion routine in the userDataPtr field to pass it around. Replace
- the completion procs with our procs in the chain. When done, call the user's proc with the completed
- parm block.
- */
- OSErr Socks_PassiveOpenAsync(SOCKSiopb* pb){
- return paramErr;
- }
-
-
-